package com.cy.model;

import com.cy.BasicModel;
import com.cy.ext.plugin.tablebind.TableBind;
import com.cy.utils.Digests;
import com.cy.utils.Encodes;
import com.jfinal.plugin.activerecord.Page;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.crypto.hash.Sha512Hash;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@TableBind(tableName="account",pkName = "account_id")
public class Account extends BasicModel<Account> {
    private static final long serialVersionUID = 458454286516394433L;

    public static final Account dao = new Account();
    public static final String SELECT_ALL = "`account_id`,`account`,`name`,`password`,`salt`,`level`,`job_no`,`department`,`mobile`,`email`,`status`,`company_id`,`create_time`,`remark`";
    private static final int SALT_SIZE = 32;
    public static final int HASH_INTERATIONS = 264544;

    @Override
    public Page<Account> paginate(Integer pageNumber, Integer pageSize, String select, Account model) {
        List<Object> paras = new ArrayList<>();
        StringBuffer sqlExceptSelectBuffer = new StringBuffer("FROM account a LEFT JOIN company c ON a.company_id = c.id WHERE 1=1");
        StringBuffer selectBuffer = new StringBuffer("SELECT ").append(select);

        pageNumber = pageNumber == null || pageNumber == 0 ? 1 : ++pageNumber;
        pageSize = pageSize == null || pageSize == 0 ? 20 : pageSize;

        if (model != null) {
            String[] attrNames = model.getAttrNames();
            for (String attrName : attrNames) {
                Object attrValue = model.get(attrName);
                if (attrValue != null) {
                    if(attrName.equals("account")) {
                        sqlExceptSelectBuffer.append(" AND a.account LIKE ? ");
                        attrValue = "%"+attrValue+"%";
                    } else if(attrName.equals("name")) {
                        sqlExceptSelectBuffer.append(" AND a.name LIKE ? ");
                        attrValue = "%"+attrValue+"%";
                    } else if(attrName.equals("job_no")) {
                        sqlExceptSelectBuffer.append(" AND a.job_no LIKE ? ");
                        attrValue = "%"+attrValue+"%";
                    } else if(attrName.equals("department")) {
                        sqlExceptSelectBuffer.append(" AND a.department LIKE ? ");
                        attrValue = "%"+attrValue+"%";
                    } else {
                        sqlExceptSelectBuffer.append(" AND `" + attrName + "`=?");
                    }
                    paras.add(attrValue);
                }
            }
        }
        return paras.size() > 0 ? paginate(pageNumber, pageSize, selectBuffer.toString(), sqlExceptSelectBuffer.toString(), paras.toArray())
                : paginate(pageNumber, pageSize, selectBuffer.toString(), sqlExceptSelectBuffer.toString());
    }

    /**
     * 根据角色查询用户
     */
    public Page<Account> pageAccountByRole(Integer pageNumber, Integer pageSize, Account account, String roleId) {
        List<Object> paras = new ArrayList<>();
        StringBuffer selectBuffer = new StringBuffer("SELECT amr.`id`,amr.`account_role_id`,a.`account_id`,a.`account`,a.`name`,a.`level`,a.`job_no`,a.`department`,a.`mobile`,a.`email`,a.`status`,a.`create_time`,a.`remark`");
        StringBuffer sqlExceptSelectBuffer = new StringBuffer("FROM account a, account_map_role amr");
        sqlExceptSelectBuffer.append(" WHERE a.account_id = amr.account_id ");
        if (pageNumber == null || pageNumber == 0) {
            pageNumber = 1;
        }else{
            pageNumber++;
        }
        if (pageSize == null || pageSize == 0) {
            pageSize = 20;
        }
        if (StringUtils.isNotEmpty(roleId)){
            sqlExceptSelectBuffer.append(" AND amr.account_role_id = "+ roleId);
        }
        if (account != null) {
            String[] attrNames = account.getAttrNames();
            for (String attrName : attrNames) {
                Object attrValue = account.get(attrName);
                if (attrValue != null) {
                    sqlExceptSelectBuffer.append(" AND `" + attrName + "`=? ");
                    paras.add(attrValue);
                }
            }
        }

        Page<Account> devicePage;
        if (paras.size() > 0){
            devicePage = paginate(pageNumber, pageSize, selectBuffer.toString(), sqlExceptSelectBuffer.toString(), paras.toArray());
        }else{
            devicePage = paginate(pageNumber, pageSize, selectBuffer.toString(), sqlExceptSelectBuffer.toString());
        }
        return devicePage;
    }

    /**
     * 根据钉钉用户查询平台账号
     * @param dingUserId
     */
    public Account findByDingUserId(String dingUserId) {
        return findFirst("SELECT a.* FROM account a, account_map_dingding amd WHERE a.account_id = amd.account_id AND amd.ding_user_id = ?", dingUserId);
    }

    /**
     * 检查用户数据是否唯一
     *
     * @param account 账号
     * @return 是否唯一
     */
    public boolean checkAccountUnique(String account) {
        boolean flag = false;

        Account orgAccount = getByAccount(account);
        if (orgAccount != null) {
            flag = true;
        }
        return flag;
    }

    @Override
    public boolean save() {
        entryptPassword();
        if (getStatus() == null) {
            setStatus(1);
        }
        if (getCreateTime() == null) {
            setCreateTime(new Date());
        }
        return super.save();
    }

    /**
     * 加密密码
     */
    public void entryptPassword() {
        String plainPassword = getStr("password");
        if (StringUtils.isNotBlank(plainPassword)) {
            byte[] salt = Digests.generateSalt(SALT_SIZE);
            setSalt(Encodes.encodeHex(salt));
            setPassword(entryptPassword(plainPassword, salt));
        }
    }

    private String entryptPassword(String plainPassword, byte[] salt) {
        Sha512Hash sha = new Sha512Hash(plainPassword, salt, HASH_INTERATIONS);
        return sha.toHex();
    }

    /**
     * 对比密码
     *
     * @param password
     * @return
     */
    public boolean matchPassword(String password) {
        String hex_password = entryptPassword(password, Encodes.decodeHex(getSalt()));
        return getPassword().equals(hex_password);
    }

    public Account getByAccount(String account){
        return findFirst("SELECT * FROM " + getTableName() + " where account = ?", account);
    }

    /**
     * 获取平台显示的菜单
     */
    public List<Menu> getPlatfromShowMenus() {
        StringBuilder sql = new StringBuilder(50);
        sql.append(" SELECT m.*");
        sql.append(" FROM account a, account_map_role amr, account_role ar, permission p,");
        sql.append(" (SELECT * FROM menu WHERE parent_id IS NULL UNION");
        sql.append(" SELECT m2.* FROM menu m1, menu m2 ");
        sql.append(" WHERE m1.id = m2.parent_id AND m1.parent_id IS NULL) m");
        sql.append(" WHERE a.account_id = amr.account_id");
        sql.append(" AND ar.id = amr.account_role_id");
        sql.append(" AND ar.id = p.account_role_id");
        sql.append(" AND m.id = p.menu_id");
        sql.append(" AND m.platform & "+ CCRM +" = "+ CCRM);
        sql.append(" AND ar.status = 1");
        sql.append(" AND m.type = ?");
        sql.append(" AND a.account_id = ?");
        sql.append(" GROUP BY m.id");
        sql.append(" ORDER BY m.id");
        return Menu.dao.find(sql.toString(), Menu.Type.PLATFROM.ordinal(), getAccountId());
    }

    /**
     * 获取钉钉显示的菜单(PC端/移动端)
     */
    public List<Menu> getDingShowMenus(Menu.Type type) {
        StringBuilder sql = new StringBuilder(50);
        sql.append(" SELECT m.*");
        sql.append(" FROM account a, account_map_role amr, account_role ar, permission p, menu m");
        sql.append(" WHERE a.account_id = amr.account_id");
        sql.append(" AND ar.id = amr.account_role_id");
        sql.append(" AND ar.id = p.account_role_id");
        sql.append(" AND m.id = p.menu_id");
        sql.append(" AND m.parent_id IS NULL");
        sql.append(" AND m.platform & "+ CCRM +" = "+ CCRM);
        sql.append(" AND ar.status = 1");
        sql.append(" AND m.type = ?");
        sql.append(" AND a.account_id = ?");
        sql.append(" GROUP BY m.id");
        sql.append(" ORDER BY m.id");
        return Menu.dao.find(sql.toString(), type.ordinal(), getAccountId());
    }

    public List<AccountRole> getRoles(){
        return AccountRole.dao.find("SELECT r.* FROM account_role r, account_map_role amr WHERE r.id = amr.account_role_id AND r.platform & "+ CCRM +" = "+ CCRM +" AND amr.account_id = ?", getAccountId());
    }

    public Account setAccountId (Long accountId){
        this.set("account_id",accountId);
        return this;
    }

    public Long getAccountId(){
        return this.get("account_id");
    }

    public Account setAccount (String account){
        this.set("account",account);
        return this;
    }

    public String getAccount (){
        return this.getStr("account");
    }

    public Account setName (String name){
        this.set("name",name);
        return this;
    }

    public String getName (){
        return this.getStr("name");
    }

    public Account setPassword (String password){
        this.set("password",password);
        return this;
    }

    public String getPassword (){
        return this.getStr("password");
    }

    public Account setSalt (String salt){
        this.set("salt",salt);
        return this;
    }

    public String getSalt(){
        return this.getStr("salt");
    }

    public Account setLevel (Integer level){
        this.set("level",level);
        return this;
    }

    public Integer getLevel (){
        return this. get("level");
    }

    public Account setJobNo (String jobNo){
        this.set("job_no",jobNo);
        return this;
    }

    public String getJobNo (){
        return this.getStr("job_no");
    }

    public Account setDepartment (String department){
        this.set("department",department);
        return this;
    }

    public String getDepartment (){
        return this.getStr("department");
    }

    public Account setMobile (String mobile){
        this.set("mobile",mobile);
        return this;
    }

    public String getMobile (){
        return this.getStr("mobile");
    }

    public Account setEmail (String email){
        this.set("email",email);
        return this;
    }

    public String getEmail (){
        return this.getStr("email");
    }

    public Account setStatus (Integer status){
        this.set("status",status);
        return this;
    }

    public Integer getStatus (){
        return this. get("status");
    }

    public Account setCreateTime (Date createTime){
        this.set("create_time",createTime);
        return this;
    }

    public Date getCreateTime (){
        return this.get("create_time");
    }

    public Account setRemark (String remark){
        this.set("remark",remark);
        return this;
    }

    public String getRemark (){
        return this.getStr("remark");
    }

    public Account setCompanyId (Long companyId){
        this.set("company_id",companyId);
        return this;
    }

    public Long getCompanyId(){
        return this.get("company_id");
    }
}